/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DAO;

import common.GeneralHandling;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.cassandra.thrift.*;
import org.apache.thrift.TException;
import pojo.Status;
import pojo.Tag;
/**
 *
 * @author huy
 */
public class StatusDAO {
    private static Cassandra.Client client;
    private static StatusDAO instance;
    
    public static StatusDAO getInstance(Cassandra.Client _client)
    {
        if (instance != null)
            return instance;
        instance = new StatusDAO();
        client = _client;
        return instance;
    }
    
    public boolean InsertStatus(Status newstatus)
    {
        boolean result = false;
        try {
            
            ColumnParent parent = new ColumnParent(Status.col_parent);
            ByteBuffer status_ID = common.GeneralHandling.toByteBuffer(UUID.randomUUID().toString());
            
            //Add các column vào CF.
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_content, newstatus.getContent()),common.Constants.CL);
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_tags, newstatus.getTags()),common.Constants.CL);
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_likecount, newstatus.getLike_count()),common.Constants.CL);
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_dislikecount, newstatus.getDislike_count()),common.Constants.CL);
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_createdate, ""),common.Constants.CL);
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_modifydate, ""),common.Constants.CL);
            client.insert(status_ID,parent,GeneralHandling.createCol(Status.colname_state, "public"),common.Constants.CL);
            
            //Cập nhật list_status_ID cho tag tương ứng.
            String[] tags = newstatus.getTags().split(",");
            TagDAO tag_DAO = TagDAO.getInstance(client);
            String x = GeneralHandling.toString(status_ID);
            for (int i = 0; i < tags.length; i++) {
                if (!tag_DAO.InsertStatusIDtoTag(x, tags[i]))
                    return result;
            }
            result = true;
        
        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return result;
    }
    
    public String SelectRandom()
    {
        String result = "";
        try {
            
            ColumnParent parent = new ColumnParent(Status.col_parent);
            
            SlicePredicate predicate = new SlicePredicate();
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_content));
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_tags));
            
            KeyRange range = new KeyRange();
            range.start_key = common.GeneralHandling.toByteBuffer("");
            range.end_key = common.GeneralHandling.toByteBuffer("");
            
            List<KeySlice> p_listkey = client.get_range_slices(parent, predicate, range, common.Constants.CL);
            int keystart = (new Random()).nextInt(/*common.Constants.countStatus*/70);
            int count = (new Random()).nextInt(5) + 6;
            List<KeySlice> listkey = p_listkey.subList(keystart, keystart + count);
            result = ParseToJSON(listkey);
        
        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
    
    public String SelectRandomtoTag(String Tagname)
    {
        String result = "";
        try {
            
            ByteBuffer rowkey = common.GeneralHandling.toByteBuffer(Tagname);
            ColumnParent parent = new ColumnParent(Tag.col_parent);
            
            SlicePredicate predicate = new SlicePredicate();
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Tag.name_scol_lstatus));
                    
            List<ColumnOrSuperColumn> result_key = client.get_slice(rowkey, parent, predicate, common.Constants.CL);
            List<ByteBuffer> listStatusID = new ArrayList<ByteBuffer>();
            for (ColumnOrSuperColumn col : result_key) {
                for (Column c : col.getSuper_column().columns)
                    listStatusID.add(c.name);
            }
            //Xáo trôn list statusID
            Random rd = new Random();
            for (int i = 0; i < listStatusID.size() - 1; i++) {
                for (int j = i + 1; j < listStatusID.size(); j++)
                {
                    if (rd.nextInt(1) < rd.nextInt(3))
                    {
                        ByteBuffer temp = listStatusID.get(i);
                        listStatusID.set(i, listStatusID.get(j));
                        listStatusID.set(j, temp);
                    }
                }
            }
            int length = rd.nextInt(5) + 6;
            if (listStatusID.size() > length)
                listStatusID = listStatusID.subList(0, length);
            result = Getliststatus(listStatusID); 
            
        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
    
    public String Getliststatus(List<ByteBuffer> listStatusID)
    {
        String result = "";
        try {
            ColumnParent parent = new ColumnParent(Status.col_parent);
            SlicePredicate predicate = new SlicePredicate();
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_content));
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_tags));
                
            Map<ByteBuffer, List<ColumnOrSuperColumn>> mapstatus = client.multiget_slice(listStatusID, parent, predicate, common.Constants.CL);
            List<KeySlice> liststatus = new ArrayList<KeySlice>();
            for (int i = 0; i < mapstatus.size(); i++)
            {
                liststatus.add(new KeySlice(listStatusID.get(i), mapstatus.get(listStatusID.get(i))));
            }
            result = ParseToJSON(liststatus);
            
        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
    
    //Lấy danh sách 20 câu status nổi bật nhất
    public String listOutstandingStatus()
    {
        String result = "";
        try {
            ColumnParent parent = new ColumnParent(Status.col_parent);
            SlicePredicate predicate = new SlicePredicate();
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_content)); 
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_likecount));
            predicate.addToColumn_names(common.GeneralHandling.toByteBuffer(Status.colname_dislikecount));
            
            KeyRange keyrange = new KeyRange();
            keyrange.start_key = common.GeneralHandling.toByteBuffer("");
            keyrange.end_key = common.GeneralHandling.toByteBuffer("");
            
            List<KeySlice> liststatus = client.get_range_slices(parent, predicate, keyrange, common.Constants.CL);
            liststatus = Sort(liststatus);
            
            result = ParseToJSON(liststatus);
            
        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
    
    private List<KeySlice> Sort(List<KeySlice> list) throws UnsupportedEncodingException
    {
        for (int i=0; i<list.size()-1; i++)
            for (int j=i+1; j<list.size(); j++)
            {
                if (OutstandingPoint(list.get(i)) < OutstandingPoint(list.get(j)))
                {
                    KeySlice temp = list.get(i);
                    list.set(i, list.get(j));
                    list.set(j, temp);
                }
            }
        List<KeySlice> result = list.subList(0, 19);
        return result;
    }
    
    //Tính điểm nổi bật của từng status like * 8 + dislike * 2
    private int OutstandingPoint(KeySlice x) throws UnsupportedEncodingException
    {
        int like = 0,dislike = 0;
        for (ColumnOrSuperColumn columnOrSuperColumn : x.getColumns()) {
            if(columnOrSuperColumn.column.name == common.GeneralHandling.toByteBuffer(Status.colname_likecount))
                like = Integer.parseInt(common.GeneralHandling.toString(columnOrSuperColumn.column.value));
            if(columnOrSuperColumn.column.name == common.GeneralHandling.toByteBuffer(Status.colname_dislikecount))
                dislike = Integer.parseInt(common.GeneralHandling.toString(columnOrSuperColumn.column.value));
        }
        return like * 8 + dislike * 2;
    }
    
    //Tăng số like lên 1
    public boolean increaseLikecount(String status_ID)
    {
        boolean result = Inscrease(status_ID,Status.colname_likecount);
        return result;
    }
    
    //Tăng số dislike lên 1
    public boolean increaseDislikecount(String status_ID)
    {
        boolean result = Inscrease(status_ID,Status.colname_dislikecount);
        return result;
    }
    
    private boolean Inscrease(String status_ID,String typecol)
    {
        boolean result = false;
        try {
            ByteBuffer id = common.GeneralHandling.toByteBuffer(status_ID);
            ColumnParent parent = new ColumnParent(Status.col_parent);
            
            ColumnPath path = new ColumnPath(Status.col_parent);
            path.column = common.GeneralHandling.toByteBuffer(typecol);
            ColumnOrSuperColumn status = client.get(id, path, common.Constants.CL);
            
            int likecount_curr = Integer.parseInt(common.GeneralHandling.toString(status.column.value));
            Column newcol = common.GeneralHandling.createCol(typecol, Integer.toString(likecount_curr + 1));
            
            client.insert(id, parent, newcol, common.Constants.CL);
            result = true;
        } catch (NotFoundException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidRequestException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnavailableException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TimedOutException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
    
    public String ParseToJSON(List<KeySlice> list)
    {
        String result = "{\"result\":[";
        for (KeySlice keySlice : list) {
            if (keySlice.columns.size() < 2)
                continue;
            try {
                result += "{\"status_ID\":\"" + common.GeneralHandling.toString(keySlice.key) + "\"";
                for (ColumnOrSuperColumn col : keySlice.columns) {
                    Column c = col.column;
                    String colname = common.GeneralHandling.toString(c.name);
                    if (colname.equals(Status.colname_content))
                        result += ",\"" + Status.colname_content + "\":\"" + common.GeneralHandling.toString(c.value) + "\"";
                    else if(colname.equals(Status.colname_tags))
                        result += ",\"" + Status.colname_tags + "\":\"" + common.GeneralHandling.toString(c.value) + "\"},";
                }
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(StatusDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        int x = result.length();
        result = result.substring(0, x - 1);
        result += "]}";
        return result;
    }
}
